﻿using System;
using System.Reflection;
using nRoute.Components.Composition;
using nRoute.Components.Messaging;
using nRoute.Utilities;

namespace nRoute.Mapping
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = false)]
    public class MapChannelObserverAttribute 
		 : MapResourceBaseAttribute
    {
        private const string MUST_BE_IMPLEMENTATION_TYPE = "{0} type must be an implementation of {1}.";
        private static readonly Type CHANNEL_GENETIC_TYPE = typeof(IObservable<>);

        private readonly Type _channelType;
        private readonly string _name;
        private readonly InitializationMode _initializationMode;

        public MapChannelObserverAttribute(Type channelType)
		    : this(channelType, null, InitializationMode.OnDemand) { }

        public MapChannelObserverAttribute(Type channelType, string name)
            : this(channelType, name, InitializationMode.OnDemand) { }

        public MapChannelObserverAttribute(Type channelType, string name, InitializationMode initializationMode)
        {
            Guard.ArgumentNotNull(channelType, "channelType");

            _channelType = channelType;
            _name = name;

            ThreadOption = ThreadOption.PublisherThread;
        }

#region Properties

        public string Name
        {
            get { return _name; }
        }

        public Type ChannelType
        {
            get { return _channelType; }
        }

        public InitializationMode InitializationMode
        {
            get { return _initializationMode; }
        }

        public string ChannelKey { get; set; }

        public Type LifetimeManagerType { get; set; }

        public ThreadOption ThreadOption { get; set; }

        public bool IsDefault { get; set; }

#endregion

#region Overrides

        protected internal override bool IsDefaultResource
        {
            get { return IsDefault; }
        }

        protected internal override Type GetResourceType(Type targetType)
        {
            return CHANNEL_GENETIC_TYPE.MakeGenericType(_channelType);
        }

        protected internal override IResourceLocator GetResourceLocator(Type targetType, ITypeBuilder typeBuilder)
        {
            var _resourceType = CHANNEL_GENETIC_TYPE.MakeGenericType(_channelType);
            var _lifetimeManager = this.LifetimeManagerType != null ? (ILifetimeManager)typeBuilder.BuildType(this.LifetimeManagerType) : new SingletonLifetimeManager();

            return new DefaultChannelObserverLocator(_name, targetType, _resourceType, this.ChannelKey, this.ThreadOption,
                _lifetimeManager, this.InitializationMode);
        }

#endregion

    }
}